/**
 * Project: topdt-jbpm
 * Copyright 2013  Top Digital Technology  Co. Ltd.
 * All right reserved.
 */
package com.topdt.jbpm.service.cmd;

import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.TaskQuery;
import org.jbpm.api.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thx.common.util.AppContext;
import com.topdt.jbpm.WorkflowException;
import com.topdt.jbpm.identity.IdFactory;
import com.topdt.jbpm.identity.IdentityService;
import com.topdt.jbpm.identity.User;
import com.topdt.jbpm.model.Application;
import com.topdt.jbpm.model.Form;
import com.topdt.jbpm.model.Todo;
import com.topdt.jbpm.model.Work;
import com.topdt.jbpm.service.Context;
import com.topdt.jbpm.service.JbpmService;

/**
 * 建立日期 : 2013-4-27 下午6:04:46<br>
 * 作者 : balance<br>
 * 模块 : <br>
 * 描述 : <br>
 * 修改历史: 序号 日期 修改人 修改原因 <br>
 * 1 <br>
 * 2 <br>
 */
public class StartWorkCmd implements Command<StartResult> {

	private String starter;

	private String starterName;

	private String appId;

	private Application app;

	private Form form;

	private Work work;

	private Context context;

	private JbpmService jbpmService;

	private ProcessInstance processInstance;

	private Map<String, Object> vars;

	private Todo todo;

	private boolean free = false;// 自由流程

	private static Logger log=LoggerFactory.getLogger(StartWorkCmd.class);

	public StartWorkCmd(String appId, String starter, Map<String, Object> vars) {
		this.appId = appId;
		this.starter = starter;
		this.vars = vars;
	}

	// 不允许调传控参数的构成函数
	@SuppressWarnings("unused")
	private StartWorkCmd() {

	}

	public StartResult execute(JbpmService jbpmService) {

		log.debug("\n启动工作开始......\n");

		this.jbpmService = jbpmService;

		log.debug("\n 开始调用identityService查询人员......\n");
		IdentityService identityService = IdFactory.getIdentityServiceFactory().getIdentityService();
		User user = identityService.getUserById(starter);
		starterName = user.getName();
		log.debug("\n ......调用identityService查询人员结束："+starterName+"\n");

		log.debug("\n开始准备数据（取出 app 和form）......\n");
		preStartWork(appId, starter);
		log.debug("\n......准备数据（取出 app 和form）完成\n");

		log.debug("\n开始创建 work......\n");
		creatWork();
		log.debug("\n......创建 work 完成\n");

		log.debug("\n开始创建 Context......\n");
		creatContext();
		log.debug("\n......创建 Context 完成\n");

		// 判断应用是否是挂接流程的应用
		if (StringUtils.isBlank(app.getFlowId()) && StringUtils.isBlank(app.getFlowKey())) {
			// 自由流程
			free = true;
			log.debug("\n是自由流程......\n");
		} else{
			log.debug("\n开始启动 JbpmProcess......\n");
			startJbpmProcess();
			log.debug("\n......启动 JbpmProcess完成\n");
		}

		log.debug("\n开始给起草人生成todo......\n");
		newTodo();
		log.debug("\n......给起草人生成todo 完成\n");

		StartResult result = new StartResult();
		result.setActivityName(todo.getActivityName());
		result.setAppId(appId);
		result.setMessage("");
		result.setTodoId(todo.getTodoId());
		result.setWorkId(work.getWorkId());

		/*LogInfo info =new LogInfo();
		info.setUserId(starter);
		info.setDate(new Date());
		info.setModule(appId.substring(app.getCompanyId().length()));
		info.setAction(Constants.ADD);
		info.setDescription(String.format(Constants.WORKDESC_ADD, starterName,work.getWorkTitle()));
		ThreadLocalContext.set(Constants.LOGINFO_KEY,info);*/
		return result;
	}

	private void newTodo() {

		todo = new Todo();

		todo.setArriveTime(new Date());
		todo.setFromUserId("");
		todo.setCompanyId(work.getCompanyId());
		if (!free) {

			Set<String> names = processInstance.findActiveActivityNames();

			if (names != null && names.size() > 0) {

				String activityName = names.iterator().next();

				TaskQuery query = jbpmService.getTaskService().createTaskQuery();
				Task task = query.processInstanceId(processInstance.getId()).activityName(activityName)
						.assignee(starter).uniqueResult();

				todo.setActivityName(activityName);
				todo.setTaskId(task.getId());
				work.setCurActivityName("[" + activityName + ":" + starterName + "]");
			}

		} else {
			work.setCurActivityName("[自由流程：起草]");
			todo.setActivityName("自由流程：起草");
		}

		todo.setToUserId(starter);
		todo.setWorkId(work.getWorkId());
		todo.setTodoTitle(work.getWorkTitle());

		todo.setState(Todo.STATE_READY);
		todo.setBatch(System.currentTimeMillis());
		todo.setAppName(app.getAppName());
		todo.setPreActivityName("开始");

		jbpmService.getTodoDao().save(todo);
		jbpmService.getWorkDao().update(work);
	}

	private void preStartWork(String appId, String starter) {
		if (StringUtils.isEmpty(appId))
			throw new WorkflowException("启动工作时传入的参数 appId（应用标示）为：" + appId + "，要求不能为空或null");

		if (StringUtils.isEmpty(starter))
			throw new WorkflowException("启动工作时传入的参数 starter（启动人）为：" + starter + "，要求不能为空或null");

		app = jbpmService.getAppDao().getById(appId);
		form = app.getForm();
	}

	private void startJbpmProcess() {

		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put(Context.KEY, context);
		variables.put("starter", this.starter);
		if (this.vars != null)
			variables.putAll(this.vars);
		processInstance = jbpmService.getExecutionService().startProcessInstanceById(app.getFlowId(), variables,
				work.getWorkId());

	}

	private void creatContext() {
		context = new Context();
		context.setAppId(app.getAppId());
		context.setFormId(form.getFormId());
		context.setWorkId(work.getWorkId());
		context.setStarter(starter);
		context.setCurrentActor(starter);
		context.setFlowId(app.getFlowId());
		context.setFlowKey(app.getFlowKey());
	}

	private void creatWork() {
		work = new Work();
		work.setAppId(app.getAppId());
		work.setFlowId(app.getFlowId());
		work.setFlowKey(app.getFlowKey());
		work.setStartTime(new Timestamp(System.currentTimeMillis()));
		work.setWorkState(Work.STATE_START);
		work.setStarter(starter);
		work.setStarterName(starterName);
//		work.setWorkTitle(app.getAppName());
		work.setAppName(app.getAppName());
		String comId = AppContext.getCurrentComId();
		work.setCompanyId(comId);
		jbpmService.getWorkDao().save(work);
	}

}
